#include <rtthread.h>
#include <rthw.h>

rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
{
    rt_list_init(&(ipc->suspend_thread));

    return RT_EOK;
}

rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t *list, struct rt_thread *thread, rt_uint8_t flag){
    struct rt_list_node *n;
    struct rt_thread *sthread;

    rt_thread_suspend(thread);
    
    switch (flag){
        case RT_IPC_FLAG_FIFO:
            rt_list_insert_before(list, &(thread->tlist));
            break;
    
        case RT_IPC_FLAG_PRIO:
            for(n = list->next; n != list; n = n->next){
                sthread = rt_list_entry(n, struct rt_thread, tlist);

                if(thread->current_priority < sthread->current_priority){
                    rt_list_insert_before(&(sthread->tlist), &(thread->tlist));

                    break;
                }
            }
            
            if(n == list)
                rt_list_insert_before(list, &(thread->tlist));

            break;
    }

    return RT_EOK;
}

rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list){
    struct rt_thread *thread;

    thread = rt_list_entry(list->next, struct rt_thread, tlist);

    rt_thread_resume(thread);

    return RT_EOK;
}

rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
{
    struct rt_thread *thread;
    register rt_ubase_t temp;

    while(!rt_list_isempty(list)){
        temp = rt_hw_interrupt_disable();

        thread = rt_list_entry(list->next, struct rt_thread, tlist);

        rt_thread_resume(thread);

        rt_hw_interrupt_enable(temp);
    }

    return RT_EOK;
}

rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag)
{
    rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);

    rt_ipc_object_init(&(sem->parent));

    sem->value = (rt_uint16_t)value;

    sem->parent.parent.flag = flag;

    return RT_EOK;
}

rt_err_t rt_sem_detach(rt_sem_t sem)
{
    rt_ipc_list_resume_all(&(sem->parent.suspend_thread));

    rt_object_detach(&(sem->parent.parent));

    return RT_EOK;
}

rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag){
    rt_sem_t sem;

    sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
    if(sem == RT_NULL){
        return RT_NULL;
    }

    rt_ipc_object_init(&sem->parent);

    sem->value = (rt_uint16_t)value;

    sem->parent.parent.flag = flag;

    return sem;
}

rt_err_t rt_sem_delete(rt_sem_t sem){
    RT_ASSERT(sem != RT_NULL);

    rt_ipc_list_resume_all(&(sem->parent.suspend_thread));

    rt_object_delete((rt_object_t)sem);

    return RT_EOK;
}

rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time){
    struct rt_thread *thread;
    register rt_ubase_t temp;

    RT_ASSERT(sem != RT_NULL);
    RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);

    temp = rt_hw_interrupt_disable();

    if(sem->value > 0){
        sem->value--;

        rt_hw_interrupt_enable(temp);
    }else{
        if(time == 0){
            rt_hw_interrupt_enable(temp);

            return -RT_ETIMEOUT;
        }else{
            thread = rt_thread_self();

            thread->error = RT_EOK;

            rt_ipc_list_suspend(&(sem->parent.suspend_thread), thread, sem->parent.parent.flag);

            if(time > 0){
                rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);

                rt_timer_start(&(thread->thread_timer));
            }

            rt_hw_interrupt_enable(temp);

            rt_schedule();

            /* 当线程恢复后，thread->error 不等于 RT_EOK 说明出错或超时 */
            if(thread->error != RT_EOK){
                return thread->error;
            }
        }
    }

    return RT_EOK;
}

rt_err_t rt_sem_trytake(rt_sem_t sem){
    return rt_sem_take(sem, 0);
}

rt_err_t rt_sem_release(rt_sem_t sem){
    rt_ubase_t temp;
    rt_bool_t need_schedule;

    RT_ASSERT(sem != RT_NULL);

    need_schedule = RT_FALSE;

    temp = rt_hw_interrupt_disable();

    if(!rt_list_isempty(&(sem->parent.suspend_thread))){    // 判断是否有挂起线程
        rt_ipc_list_resume(&(sem->parent.suspend_thread));  // 有，则唤起一个
        need_schedule = RT_TRUE;
    }else{
        sem->value++;
    }

    rt_hw_interrupt_enable(temp);

    if(need_schedule)
        rt_schedule();

    return RT_EOK;
}

rt_err_t rt_sem_contrl(rt_sem_t sem, int cmd, void *arg){
    rt_ubase_t tmp;

    RT_ASSERT(sem != RT_NULL);

    if(cmd == RT_IPC_CMD_RESET){
        tmp = rt_hw_interrupt_disable();

        rt_ipc_list_resume_all(&(sem->parent.suspend_thread));

        sem->value = (rt_uint16_t)arg;

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    return -RT_ERROR;
}


rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag){
    RT_ASSERT(mutex != RT_NULL);

    rt_object_init(&mutex->parent.parent, RT_Object_Class_Mutex, name);

    rt_ipc_object_init(&mutex->parent);

    mutex->parent.parent.flag = flag;
    mutex->value = 1;
    mutex->original_priority = RT_THREAD_PRIORITY_MAX - 1;
    mutex->hold = 0;
    mutex->owner = RT_NULL;

    return RT_EOK;
}

rt_err_t rt_mutex_detach(rt_mutex_t mutex){
    rt_thread_t thread;
    rt_ubase_t tmp;

    RT_ASSERT(mutex != RT_NULL);

    rt_ipc_list_resume_all(&mutex->parent.suspend_thread);

    rt_object_detach((rt_object_t)mutex);

    return RT_EOK;
}

rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag){
    rt_mutex_t mutex;
    
    RT_ASSERT(mutex != RT_NULL);

    mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
    if(mutex == RT_NULL){
        return mutex;
    }

    rt_ipc_object_init(&mutex->parent);

    mutex->parent.parent.flag = flag;
    mutex->value = 1;
    mutex->original_priority = RT_THREAD_PRIORITY_MAX - 1;
    mutex->hold = 0;
    mutex->owner = RT_NULL;

    return mutex;
}

rt_err_t rt_mutex_delete(rt_mutex_t mutex){
    RT_ASSERT(mutex != RT_NULL);

    rt_ipc_list_resume_all(&mutex->parent.suspend_thread);

    rt_object_delete((rt_object_t)mutex);

    return RT_EOK;
}

rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time){
    rt_thread_t thread;
    rt_base_t tmp;

    RT_ASSERT(mutex != RT_NULL);

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    thread->error = RT_EOK;

    if(mutex->owner == thread){
        mutex->hold++;
    }else{
        if(mutex->value > 0){
            mutex->value--;

            mutex->owner = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold++;
        }else{
            if(time == 0){
                thread->error = -RT_ETIMEOUT;

                rt_hw_interrupt_enable(tmp);

                return -RT_ETIMEOUT;
            }

            if(mutex->original_priority > thread->current_priority){
                rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY, &thread->current_priority);
            }

            rt_ipc_list_suspend(&mutex->parent.suspend_thread, thread, mutex->parent.parent.flag);

            if(time > 0){
                rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, &time);
                rt_timer_start(&thread->thread_timer);
            }

            rt_hw_interrupt_enable(tmp);

            rt_schedule();

            if(thread->error != RT_EOK){
                return thread->error;
            }

            tmp = rt_hw_interrupt_disable();
        }
        
    }

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mutex_release(rt_mutex_t mutex){
    rt_thread_t thread;
    rt_base_t tmp;
    rt_bool_t need_schedule = RT_FALSE;

    RT_ASSERT(mutex != RT_NULL);

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    if(mutex->owner != thread){
        thread->error = -RT_ERROR;

        rt_hw_interrupt_enable(tmp);

        return -RT_ERROR;
    }

    mutex->hold--;

    if(mutex->hold == 0){
        if(mutex->original_priority != mutex->owner->current_priority){
            rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY, &(mutex->original_priority));
        }

        if(!rt_list_isempty(&mutex->parent.suspend_thread)){
            thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist);

            mutex->owner = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold++;

            rt_ipc_list_resume(&mutex->parent.suspend_thread);

            need_schedule = RT_TRUE;
        }else{
            mutex->value++;

            mutex->owner = RT_NULL;
            mutex->original_priority = RT_THREAD_PRIORITY_MAX - 1;
        }
    }

    rt_hw_interrupt_enable(tmp);

    if(need_schedule){
        rt_schedule();
    }

    return RT_EOK;
}

rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg){
    RT_ASSERT(mutex != RT_NULL);

    return -RT_ERROR;
}

rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag){
    RT_ASSERT(event != RT_NULL);

    rt_object_init(&event->parent.parent, RT_Object_Class_Event, name);

    rt_ipc_object_init(&event->parent);

    event->parent.parent.flag = flag;

    event->set = 0;

    return RT_EOK;
}

rt_err_t rt_event_detach(rt_event_t event){
    RT_ASSERT(event != RT_NULL);

    rt_ipc_list_resume_all(&event->parent.suspend_thread);

    rt_object_detach(&event->parent.parent);

    event->set = 0;

    return RT_EOK;
}

rt_event_t rt_event_create(const char *name, rt_uint8_t flag){
    rt_event_t event;

    event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name);
    if(event == RT_NULL){
        return event;
    }

    rt_ipc_object_init(&(event->parent));

    event->parent.parent.flag = flag;

    event->set = 0;

    return event;
}

rt_err_t rt_event_delete(rt_event_t event){
    RT_ASSERT(event != RT_NULL);

    rt_ipc_list_resume_all(&event->parent.suspend_thread);

    rt_object_delete(&event->parent.parent);

    return RT_EOK;
}

rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set){
    rt_ubase_t tmp;
    rt_thread_t thread;
    struct rt_list_node *n;
    rt_base_t status;
    rt_bool_t need_schedule = RT_FALSE;

    RT_ASSERT(event != RT_NULL);

    if(set == 0){
        return -RT_ERROR;
    }

    tmp = rt_hw_interrupt_disable();

    event->set |= set;

    if(!rt_list_isempty(&event->parent.suspend_thread)){
        n = event->parent.suspend_thread.next;

        while(n != &event->parent.suspend_thread){
            thread = rt_list_entry(n, struct rt_thread, tlist);

            status = -RT_ERROR;

            if(thread->event_info & RT_EVENT_FLAG_AND){
                if((thread->event_set & event->set) == thread->event_set){
                    status = RT_EOK;
                }
            }else if(thread->event_info & RT_EVENT_FLAG_OR){
                if(thread->event_set & event->set){
                    thread->event_set = thread->event_set & event->set;

                    status = RT_EOK;
                }
            }

            n = n->next;

            if(status == RT_EOK){
                if(thread->event_info & RT_EVENT_FLAG_CLEAR){
                    event->set &= ~thread->event_set;
                }

                rt_thread_resume(thread);   // 如果 n=n->next 放在后面，就改变了链表指向。

                need_schedule = RT_TRUE;
            }
        }
    }

    rt_hw_interrupt_enable(tmp);

    if(need_schedule == RT_TRUE){
        rt_schedule();
    }

    return RT_EOK;
}

rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option,
                       rt_int32_t timeout, rt_uint32_t *recved){
    rt_ubase_t tmp;
    rt_thread_t thread;
    rt_base_t status = -RT_ERROR;
    rt_ubase_t tick_delta;

    RT_ASSERT(event != RT_NULL);

    if (set == 0)
        return -RT_ERROR;

    thread = rt_thread_self();
    thread->error = RT_EOK;

    tmp = rt_hw_interrupt_disable();

    if(option & RT_EVENT_FLAG_AND){
        if((event->set & set) == set){
            status = RT_EOK;
        }
    }else if(option & RT_EVENT_FLAG_OR){
        if(event->set & set){
            status = RT_EOK;
        }
    }

    if(status == RT_EOK){
        if(recved)
            *recved = (event->set & set);

        if(option & RT_EVENT_FLAG_CLEAR){
            event->set &= ~set;
        }
    }else if(timeout == 0){
            thread->error = -RT_ETIMEOUT;
    }else{
        thread->event_info = option;
        thread->event_set = set;

_again:
        thread->error = RT_EOK;
        rt_ipc_list_suspend(&event->parent.suspend_thread, thread, event->parent.parent.flag);

        if(timeout > 0){
            tick_delta = rt_tick_get();

            rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, &timeout);
            rt_timer_start(&thread->thread_timer);
        }

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        if(thread->error == -RT_EINTR){     // 接收到signal，被恢复
            if(timeout > 0){
                tick_delta = rt_tick_get() - tick_delta;
                timeout -= tick_delta;
                if(timeout < 0){
                    timeout = 0;
                }
            }

            goto _again;
        }

        if(thread->error != RT_EOK){
            return thread->error; 
        }

        tmp = rt_hw_interrupt_disable();

        if(recved)
            *recved = thread->event_set;
    }

    rt_hw_interrupt_enable(tmp);

    return thread->error;
}

rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg){
    rt_ubase_t level;

    RT_ASSERT(event != RT_NULL);

    if (cmd == RT_IPC_CMD_RESET){
        level = rt_hw_interrupt_disable();

        rt_ipc_list_resume_all(&event->parent.suspend_thread);

        event->set = 0;

        rt_hw_interrupt_enable(level);

        rt_schedule();

        return RT_EOK;
    }

    return -RT_ERROR;
}


rt_err_t rt_mb_init(rt_mailbox_t mb,
                    const char  *name,
                    void        *msgpool,
                    rt_size_t    size,
                    rt_uint8_t   flag){
    RT_ASSERT(mb != RT_NULL);

    rt_object_init(&mb->parent.parent, RT_Object_Class_MailBox, name);

    rt_ipc_object_init(&mb->parent);
    mb->parent.parent.flag = flag;
    mb->msg_pool = msgpool;
    mb->size = size - 1;    // 计数从0开始
    mb->entry = 0;
    mb->in_offset = 0;
    mb->out_offset = 0;

    rt_list_init(&mb->suspend_sender_thread);

    return RT_EOK;
}

rt_err_t rt_mb_detach(rt_mailbox_t mb){
    RT_ASSERT(mb != RT_NULL);

    rt_ipc_list_resume_all(&mb->parent.suspend_thread);
    rt_ipc_list_resume_all(&mb->suspend_sender_thread);
    rt_object_detach(&mb->parent.parent);

    return RT_EOK;
}


rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag){
    rt_mailbox_t mb;
    rt_uint32_t *msgpool;

    mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name);
    if(mb == RT_NULL){
        return mb;
    }

    mb->msg_pool = (rt_uint32_t *)rt_malloc(size);
    if(mb->msg_pool == RT_NULL){
        rt_object_delete(&mb->parent.parent);

        return RT_NULL;
    }

    rt_ipc_object_init(&mb->parent);

    mb->parent.parent.flag = flag;
    mb->size = size - 1;
    mb->entry = 0;
    mb->in_offset = 0;
    mb->out_offset = 0;

    rt_list_init(&mb->suspend_sender_thread);

    return mb;
}

rt_err_t rt_mb_delete(rt_mailbox_t mb){
    RT_ASSERT(mb != RT_NULL);

    rt_ipc_list_resume_all(&mb->parent.suspend_thread);
    rt_ipc_list_resume_all(&mb->suspend_sender_thread);

    rt_free(mb->msg_pool);

    rt_object_delete(&mb->parent.parent);

    return RT_EOK;
}

rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
                         rt_ubase_t  value,
                         rt_int32_t   timeout){
    rt_ubase_t tmp;
    rt_thread_t thread;
    rt_base_t ticked;

    RT_ASSERT(mb != RT_NULL);

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    while(mb->entry == mb->size){   // 邮箱池满
        thread->error = RT_EOK;

        if(timeout == 0){
            rt_hw_interrupt_enable(tmp);

            thread->error = -RT_EFULL;

            return -RT_EFULL;
        }

        rt_ipc_list_suspend(&mb->suspend_sender_thread, thread, mb->parent.parent.flag);

        if(timeout > 0){
            ticked = rt_tick_get();

            rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, &timeout);
            rt_timer_start(&thread->thread_timer);
        }

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        /* 线程恢复后如果 != RT_EOK，则表示超时或其他错误 */
        if(thread->error != RT_EOK){
            return  thread->error;
        }

        tmp = rt_hw_interrupt_disable();

        if(timeout > 0){
            ticked = rt_tick_get() - ticked;
            timeout -= ticked;
            if(timeout < 0){
                timeout = 0;
            }
        }
    }

    /* 退出循环表示邮箱池有空闲 */
    mb->msg_pool[mb->in_offset] = value;
    mb->in_offset++;
    if(mb->in_offset >= mb->size){
        mb->in_offset = 0;
    }

    mb->entry++;
    
    /* 如果有接受线程在等待邮箱 */
    if(!rt_list_isempty(&mb->parent.suspend_thread)){
        rt_ipc_list_resume(&mb->parent.suspend_thread);

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value){
    return rt_mb_send_wait(mb, value, 0);
}

rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout){
    rt_thread_t thread;
    rt_ubase_t tmp;
    rt_base_t ticked;

    RT_ASSERT(mb != RT_NULL);

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    while(mb->entry == 0){  // 空
        thread->error = RT_EOK;

        if(timeout == 0){
            rt_hw_interrupt_enable(tmp);

            thread->error = -RT_ETIMEOUT;

            return -RT_ETIMEOUT;
        }

        rt_ipc_list_suspend(&mb->parent.suspend_thread, thread, mb->parent.parent.flag);

        if(timeout > 0){
            rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, &timeout);
            rt_timer_start(&thread->thread_timer);
        }

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        if(thread->error != RT_EOK){
            return thread->error;
        }

        tmp = rt_hw_interrupt_disable();

        if(timeout > 0){
            ticked = rt_tick_get() - ticked;
            timeout -= ticked;
            if(timeout < 0){
                timeout = 0;
            }
        }
    }

    if(value){
        *value = mb->msg_pool[mb->out_offset];
    }

    mb->entry--;
    mb->out_offset++;
    if(mb->out_offset >= mb->size){
        mb->out_offset = 0;
    }

    /* 如果有发送线程在等待空位 */
    if(!rt_list_isempty(&mb->suspend_sender_thread)){
        rt_ipc_list_resume(&mb->suspend_sender_thread);

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg){
    rt_ubase_t tmp;

    RT_ASSERT(mb != RT_NULL);

    if (cmd == RT_IPC_CMD_RESET){
        tmp = rt_hw_interrupt_disable();

        rt_ipc_list_resume_all(&mb->suspend_sender_thread);
        rt_ipc_list_resume_all(&mb->parent.suspend_thread);

        mb->entry = 0;
        mb->in_offset = 0;
        mb->out_offset = 0;

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    return RT_EOK;
}



struct rt_mq_message
{
    struct rt_mq_message *next;
};

rt_err_t rt_mq_init(rt_mq_t     mq,
                    const char *name,
                    void       *msgpool,
                    rt_size_t   msg_size,
                    rt_size_t   pool_size,
                    rt_uint8_t  flag){
    rt_base_t tmp;
    struct rt_mq_message *head;

    RT_ASSERT(mq != RT_NULL);

    rt_object_init(&mq->parent.parent, RT_Object_Class_MessageQueue, name);

    rt_ipc_object_init(&mq->parent);

    mq->parent.parent.flag = flag;
    mq->entry = 0;
    mq->msg_pool = msgpool;
    mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
    mq->max_msgs = pool_size / (mq->msg_size + sizeof(rt_uint8_t *));

    mq->msg_queue_head = RT_NULL;
    mq->msg_queue_tail = RT_NULL;

    mq->msg_queue_free = RT_NULL;
    for(tmp = 0; tmp < mq->max_msgs; tmp++){
        head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + tmp * (mq->msg_size + sizeof(struct rt_mq_message)));
        head->next = mq->msg_queue_free;
        mq->msg_queue_free = head;
    }

    return RT_EOK;
}

rt_err_t rt_mq_detach(rt_mq_t mq){
    RT_ASSERT(mq != RT_NULL);

    rt_ipc_list_resume_all(&mq->parent.suspend_thread);

    rt_object_detach(&mq->parent.parent);

    return RT_EOK;
}

rt_mq_t rt_mq_create(const char *name,
                     rt_size_t   msg_size,
                     rt_size_t   max_msgs,
                     rt_uint8_t  flag){
    rt_mq_t mq;
    struct rt_mq_message *head;
    rt_base_t tmp;

    RT_ASSERT(mq != RT_NULL);

    mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name);
    if(mq == RT_NULL){
        return mq;
    }

    mq->parent.parent.flag = flag;

    rt_ipc_object_init(&mq->parent);

    mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
    mq->max_msgs = max_msgs;

    mq->msg_pool = rt_malloc((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs);
    if(mq->msg_pool == RT_NULL){
        rt_object_delete(&mq->parent.parent);

        return RT_NULL;
    }
    
    mq->entry = 0;

    mq->msg_queue_head = RT_NULL;
    mq->msg_queue_tail = RT_NULL;
    mq->msg_queue_free = RT_NULL;

    for(tmp = 0; tmp < mq->max_msgs; tmp++){
        head = (struct rt_mq_message*)((rt_uint8_t *)mq->msg_pool + tmp * (mq->msg_size + sizeof(struct rt_mq_message)));
        head->next = mq->msg_queue_free;
        mq->msg_queue_free = head;
    }

    return mq;
}
rt_err_t rt_mq_delete(rt_mq_t mq){
    RT_ASSERT(mq != RT_NULL);

    rt_ipc_list_resume_all(&mq->parent.suspend_thread);

    rt_free(mq->msg_pool);

    rt_object_delete(&mq->parent.parent);

    return RT_EOK;
}

rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size){
    struct rt_mq_message *msg;
    rt_ubase_t tmp;

    RT_ASSERT(mq != RT_NULL);

    if(size > mq->msg_size){
        return -RT_ERROR;
    }

    tmp = rt_hw_interrupt_disable();

    msg = mq->msg_queue_free;
    if(msg == RT_NULL){
        rt_hw_interrupt_enable(tmp);
        
        return -RT_EFULL;
    }

    mq->msg_queue_free = msg->next;

    rt_hw_interrupt_enable(tmp);

    msg->next = RT_NULL;

    rt_memcpy((void *)(msg+1), buffer, size);

    tmp = rt_hw_interrupt_disable();

    if(mq->msg_queue_tail != RT_NULL){
        ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg;
    }
    mq->msg_queue_tail = msg;

    if(mq->msg_queue_head == RT_NULL){
        mq->msg_queue_head = msg;
    }

    mq->entry++;

    if(!rt_list_isempty(&mq->parent.suspend_thread)){
        rt_ipc_list_resume(&mq->parent.suspend_thread);

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size){
    struct rt_mq_message *msg;
    rt_ubase_t tmp;

    RT_ASSERT(mq != RT_NULL);

    if(size > mq->msg_size){
        return -RT_ERROR;
    }

    tmp = rt_hw_interrupt_disable();

    msg = (struct rt_mq_message *)mq->msg_queue_free;
    if(msg == RT_NULL){
        rt_hw_interrupt_enable(tmp);

        return -RT_EFULL;
    }

    mq->msg_queue_free = msg->next;

    rt_hw_interrupt_enable(tmp);

    rt_memcpy((void *)(msg + 1), buffer, size);

    tmp = rt_hw_interrupt_disable();

    msg->next = mq->msg_queue_head;
    mq->msg_queue_head = msg;

    if(mq->msg_queue_free == RT_NULL){
        mq->msg_queue_free = msg;
    }

    mq->entry++;

    if(!rt_list_isempty(&mq->parent.suspend_thread)){
        rt_ipc_list_resume(&mq->parent.suspend_thread);

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        return RT_EOK;
    }

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mq_recv(rt_mq_t    mq,
                    void      *buffer,
                    rt_size_t  size,
                    rt_int32_t timeout){
    struct rt_mq_message *msg;
    rt_thread_t thread;
    rt_uint32_t tick_delta;
    rt_ubase_t tmp;

    RT_ASSERT(mq != RT_NULL);

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    while(mq->entry == 0){
        thread->error = RT_EOK;

        if(timeout == 0){
            rt_hw_interrupt_enable(tmp);

            thread->error = -RT_ETIMEOUT;

            return thread->error;
        }

        rt_ipc_list_suspend(&mq->parent.suspend_thread, thread, mq->parent.parent.flag);

        if(timeout > 0){
            tick_delta = rt_tick_get();

            rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, timeout);
            rt_timer_start(&thread->thread_timer);
        }

        rt_hw_interrupt_enable(tmp);

        rt_schedule();

        if(thread->error != RT_EOK){
            return thread->error;
        }

        tmp = rt_hw_interrupt_disable();

        if(timeout > 0){
            tick_delta = rt_tick_get() - tick_delta;
            timeout -= tick_delta;
            if(timeout < 0){
                timeout = 0;
            }
        }
    }

    msg = (struct rt_mq_message *)mq->msg_queue_head;
    mq->msg_queue_head = msg->next;

    if(mq->msg_queue_tail == msg){
        mq->msg_queue_tail = RT_NULL;   // 说明只有一个消息块，取走后要更新
    }

    mq->entry--;

    rt_hw_interrupt_enable(tmp);

    rt_memcpy(buffer, (void *)(msg + 1), size < mq->msg_size ? size : mq->msg_size);

    tmp = rt_hw_interrupt_disable();

    /* 更新空闲指针 */
    msg->next = (struct rt_mq_message *)mq->msg_queue_free;
    mq->msg_queue_free = msg;

    rt_hw_interrupt_enable(tmp);

    return RT_EOK;
}

rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg){
    rt_ubase_t level;
    struct rt_mq_message *msg;

    RT_ASSERT(mq != RT_NULL);

    if(cmd == RT_IPC_CMD_RESET){
        rt_ipc_list_resume_all(&mq->parent.suspend_thread);

        while(mq->msg_queue_head != RT_NULL){
            msg = (struct rt_mq_message *)mq->msg_queue_head;

            mq->msg_queue_head = msg->next;

            if(mq->msg_queue_tail == msg){
                mq->msg_queue_tail = RT_NULL;
            }
            
            msg->next = (struct rt_mq_message *)mq->msg_queue_free;
            mq->msg_queue_free = msg;
        }
        mq->entry = 0;

        rt_hw_interrupt_enable(level);

        rt_schedule();

        return RT_EOK;
    }

    return -RT_ERROR;
}